/**
 * @Title: TestRSA1.java
 * @Package: org.person.dfw.encrypt.asymenc
 * @author: 丰伟
 * @date: 2017年5月3日 下午5:30:53
 * @version: V1.0
 */
package name.katlog;

import static org.junit.Assert.assertTrue;

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.junit.Before;
import org.junit.Test;

/**
 * @moudle: TestRSA1
 * @version:v1.0
 * @author: 丰伟
 * @date: 2017年5月3日 下午5:30:53
 *
 */
public class TestRSA1 {
    
    /** 数字签名  密钥算法*/
    public static final String KEY_ALGORITHM = "RSA";
    /** 数字签名  签名/验证算法*/
    public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
    /** 公钥*/
    private static final String PUBLIC_KEY = "RSAPublicKey";
    /**私钥 */
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /** RSA密钥长度 默认1024位， 密钥长度必须是64的倍数，范围在512至65536位之间 */
    private static final int KEY_SIZE = 512;

    /**
     * 签名
     * @param data  待签名数据
     * @param privateKey  私钥
     * @return byte[] 数字签名
     * @throws Exception
     */
    public static byte[] sign(byte[] data, byte[] privateKey)
        throws Exception {

        // 转换私钥材料
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
        // 实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 实例化Signature
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        // 初始化Signature
        signature.initSign(priKey);
        // 更新
        signature.update(data);
        // 签名
        return signature.sign();
    }

    /**
     * 校验
     * @param data  待校验数据
     * @param publicKey 公钥
     * @param sign   数字签名
     * @return boolean 校验成功返回true 失败返回false
     * @throws Exception
     */
    public static boolean verify(byte[] data, byte[] publicKey, byte[] sign)
        throws Exception {

        // 转换公钥材料
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        // 实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 生成公钥
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        // 实例化Signature
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        // 初始化Signature
        signature.initVerify(pubKey);
        // 更新
        signature.update(data);
        // 验证
        return signature.verify(sign);
    }

    /**
     * 取得私钥
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap)
        throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
     * 取得公钥
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap)
        throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }

    /**
     * 初始化密钥
     * @return Map 密钥对儿 Map
     * @throws Exception
     */
    public static Map<String, Object> initKey()
        throws Exception {
        // 实例化密钥对儿生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        // 初始化密钥对儿生成器
        keyPairGen.initialize(KEY_SIZE);
        // 生成密钥对儿
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 封装密钥
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
    
    /** 公钥*/
    private byte[] publicKey;

    /**私钥 */
    private byte[] privateKey;

    /**
     * 初始化密钥
     * @throws Exception
     */
    @Before public void initKey1() throws Exception {

        Map<String, Object> keyMap = TestRSA1.initKey();
        publicKey = TestRSA1.getPublicKey(keyMap);
        privateKey = TestRSA1.getPrivateKey(keyMap);

        System.err.println("公钥: \n" + Base64.encodeBase64String(publicKey));
        System.err.println("私钥： \n" + Base64.encodeBase64String(privateKey));
    }

    /**
     * 校验
     * @throws Exception
     */
    @Test public void testSign() throws Exception {
        String inputStr = "RSA数字签名";
        byte[] data = inputStr.getBytes();
        // 产生签名
        byte[] sign = TestRSA1.sign(data, privateKey);
        System.err.println("签名:\n" + Hex.encodeHexString(sign));
        // 验证签名
        boolean status = TestRSA1.verify(data, publicKey, sign);
        System.err.println("状态:\n" + status);
        assertTrue(status);
    }
}
